Skip to content

fix(auth): guard against silent subpath loss when AS metadata discovery fails#1807

Open
lanxevo3 wants to merge 3 commits intomodelcontextprotocol:mainfrom
lanxevo3:fix/auth-url-subpath-guard
Open

fix(auth): guard against silent subpath loss when AS metadata discovery fails#1807
lanxevo3 wants to merge 3 commits intomodelcontextprotocol:mainfrom
lanxevo3:fix/auth-url-subpath-guard

Conversation

@lanxevo3
Copy link
Copy Markdown

When discoverAuthorizationServerMetadata() returns undefined (AS metadata endpoint returns 4xx or is unreachable), the SDK falls back to constructing authorization URLs using root-path defaults:

authorizationUrl = new URL('/authorize', authorizationServerUrl);

The problem: new URL('/authorize', 'https://example.com/admin') silently resolves to https://example.com/authorize — the /admin subpath is completely lost. The actual correct endpoint https://example.com/admin/oauth/authorize is never reached, and no error is thrown.

Reproduction

  1. PRM returns authorization_servers: ["https://example.com/admin"]
  2. AS metadata at https://example.com/.well-known/oauth-authorization-server/admin returns 404
  3. SDK constructs new URL('/authorize', 'https://example.com/admin')https://example.com/authorize
  4. User is silently redirected to a nonexistent endpoint

Fix

Added a guard at all three fallback locations (/authorize, /token, /register):

} else {
    if (authorizationServerUrl.pathname !== '/') {
        throw new Error(
            `AS metadata discovery failed for '${authorizationServerUrl.href}'. ` +
            `Cannot safely construct '/authorize' — the server URL has a non-root path. ` +
            `Ensure the AS metadata endpoint is reachable at ` +
            `'${authorizationServerUrl.origin}/.well-known/oauth-authorization-server${authorizationServerUrl.pathname}'`
        );
    }
    authorizationUrl = new URL('/authorize', authorizationServerUrl);
}

The guard throws an informative error instead of silently producing a broken URL. The root-path fallback is kept for legitimate cases where the AS is at the domain root.

Fixes #1716.

OAuth 2.1 §3.2 requires token endpoint requests to use
application/x-www-form-urlencoded regardless of grant type.

Add an explicit header.set() call immediately before the fetch in
executeTokenRequest() to prevent any addClientAuthentication
implementation from accidentally overriding the Content-Type.

Fixes modelcontextprotocol/inspector#1160
…ry fails

When discoverAuthorizationServerMetadata() returns undefined, the SDK falls back
to constructing /authorize, /token, or /register from the authorizationServerUrl.
new URL('/authorize', 'https://example.com/admin') silently resolves to
https://example.com/authorize — the '/admin' subpath is completely lost.

This affects servers with non-root AS URLs (e.g. PRM returns
https://example.com/admin but the actual endpoints are at /admin/oauth/authorize).

The fix adds a guard at all three fallback locations: if pathname !== '/',
throw an informative error explaining the discovery failure and pointing to
the correct metadata endpoint, instead of silently producing a broken URL.

Fixes modelcontextprotocol#1716.
@lanxevo3 lanxevo3 requested a review from a team as a code owner March 28, 2026 19:41
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 28, 2026

⚠️ No Changeset found

Latest commit: d16f219

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

startAuthorization silently redirects to wrong URL when AS metadata discovery fails for non-root paths

1 participant